<html>
<head>
<title>Returning values from objc_msgSend etc</title>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />           
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="rococoa.css" title="Default" />
</head>
<body>
<h1>Returning values from objc_msgSend etc</h1>

<h2>Here is my understanding so far</h2>

<p>From the 
<a href="http://developer.apple.com/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html#//apple_ref/c/func/objc_msgSend">
Objective-C 2.0 Runtime Reference</a>:

<pre class="block">
id objc_msgSend(struct objc_super *super, SEL op,  ...)
void objc_msgSend_stret(void * stretAddr, id theReceiver, SEL theSelector,  ...)
</pre>

<q>When it encounters a method call, the compiler generates a call to one of the
functions objc_msgSend, objc_msgSend_stret, objc_msgSendSuper, or
objc_msgSendSuper_stret. Messages sent to an object's superclass (using the
super keyword) are sent using objc_msgSendSuper; other messages are sent using
objc_msgSend. Methods that have data structures as return values are sent using
objc_msgSendSuper_stret and objc_msgSend_stret.</q></p>

<p>So for methods returning id or int I call objc_msgSendSuper, casting the result 
to the known return type of the method. So far so good.</p>

<p>Now to return structs I have to call objc_msgSend_stret. This is
complicated (not that the previous reference mentions this), because, from 
objc-runtime.h:

<pre class="block">
/* Struct-returning Messaging Primitives (prototypes)
 *
 * For historical reasons, the prototypes for the struct-returning 
 * messengers are unusual. The portable, correct way to call these functions 
 * is to cast them to your desired return type first.
 * 
 * For example, `NSRect result = [myNSView frame]` could be written as:
 *   NSRect (*msgSend_stret_fn)(id, SEL, ...) = (NSRect(*)(id, SEL, ...))objc_msgSend_stret;
 *   NSRect result = (*msgSend_stret_fn)(myNSView, @selector(frame));
 * or, without the function pointer:
 *   NSRect result = (*(NSRect(*)(id, SEL, ...))objc_msgSend_stret)(myNSView, @selector(frame));
 * 
 * BE WARNED that these prototypes have changed in the past and will change 
 * in the future. Code that uses a cast like the example above will be 
 * unaffected. 
 */
</pre></p>
 
<p>What I think this means is that despite the prototype saying that the
function returns void and takes void*, in reality it doesn't take void* at all,
does return a struct by value on
the stack, and your calling code had better clean it up. In C the way to make
this happen is to cast the function pointer to a pointer to a function that does
return the correct struct by value, thus tricking the compiler into generating
the correct cleanup code.</p>

<p>If you don't have a C compiler handy to do this for you, this is going to be 
tricky. Luckily Rococoa uses <a href="http://jna.dev.java.net">JNA</a>, which 
in turns uses <a href="http://sourceware.org/libffi/">libffi</a>, which is very 
close to having a C compiler to hand at runtime. Armed with a description of the
structure being returned, libffi sorts out the call stack after the call.</p>

<p>It turns out that libffi doesn't only help with objc_msgSend_stret. It surprised
me early on with Rococoa that I could call objc_msgSend as if it returned Java long, 
and everything worked OK. This didn't make sense, as a long is larger that an id
by some 32 bits. Now, not documented in objc-runtime.h, but in the 
<a href="http://developer.apple.com/documentation/MacOSX/Conceptual/universal_binary/universal_binary_tips/chapter_5_section_23.html">
Universal Binary Programming Guidelines, Second Edition</a> it says that you 
should pull the cast function pointer stunt with objc_msgSend as well.</p>

<q>If your application directly calls the Objective-C runtime function objc_msgSend,
you should always cast to the appropriate return value. For instance, for a method
that returns a BOOL data type, the following code executes properly on a PPC Macintosh
but might not on an Intel-based Macintosh computer:

<pre class="block">
BOOL isEqual = objc_msgSend(string, @selector("isEqual:"), otherString);
</pre>

To ensure that the code does executes properly on an Intel-based Macintosh computer,
you would change the code to the following:

<pre class="block">
BOOL isEqual = ((BOOL (*)(id, SEL, id))objc_msgSend)(object, @selector("isEqual:"), otherString);
</pre></q>

<p>So our long test is passing because the we are calling objc_msgSend through libffi, 
telling it that the function returns 64 bits. Libffi obligingly fixes up the stack
as if 64 bits were returned, which it turns out they were, as objc_msgSend has
played the same game of hack the stack as objc_msgSend_stret. Or at least that
is my interpretation. I can't find any reference that says that this is actually
what happens when returning a long. (Also, returning a long does not work this way on PPC.)</p>

<p>Just when I thought that I understood the rules, I tried calling a method that
returns NSSize. This is a struct, so objc_msgSend_stret applies. Except that it
doesn't. A bit of Googling yielded 
<a href="http://www.cocoabuilder.com/archive/message/cocoa/2006/6/25/166236">this</a>, 
which says:</p>

<q>This fails because the struct type is NSPoint. In the i386 function
call ABI, sufficiently small structs like NSPoint are returned in
registers instead of in memory. In this case, you need to use
objc_msgSend() (cast to return NSPoint). objc_msgSend_stret() only
works for structs returned in memory. The PPC ABI returns eight-byte
structs in memory, so objc_msgSend_stret() is the correct call there.</q>

<p>Ooh, another special case, not even hinted at in the docs seen so far. 
The post includes a link to the 
<a href="http://developer.apple.com/documentation/DeveloperTools/Conceptual/LowLevelABI/Introduction.html">
Mac OS X ABI Function Call Guide</a> which is dense, and doesn't describe when
to use objc_msgSend or objc_msgSend_stret. It does say that 8 byte structs are
returned in registers in IA-32 and memory for PPC-32, which I guess hints at the
differentiation.</p>

<p>Finally, we have <code>double objc_msgSend_fpret(id self, SEL op, ...)</code>.
The <a href="http://developer.apple.com/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html#//apple_ref/c/func/objc_msgSend_fpret">
Objective-C 2.0 Runtime Reference</a> says:<p>

<q>On the i386 platform, the ABI for functions returning a floating-point value 
is incompatible with that for functions returning an integral type. On the i386 
platform, therefore, you must use objc_msgSend_fpret for functions that for 
functions returning non-integral type. For float or long double return types, 
cast the function to an appropriate function pointer type first.<br/>
This function is not used on the PPC or PPC64 platforms.</q></p>

<p>But Rococoa has been happily passing test which return float and double from
objC_msgSend on Intel, as I didn't know about this function. In fact, the only use I've yet found for 
objc_msgSend_fpret is allowing me to interpret the stret in objc_msgSend_stret
as STructRET!</p>

<h2>Outstanding Questions</h2>

<ul>
<li>Am I right so far, or am have I got the wrong end of the stick?</li>

<li>If both objc_msgSend_stret and objc_msgSend hack the stack to return different sized
return values, why are there 2 functions?</li>

<li>Should I call objc_msgSend_stret when returning longs on PPC?</li>

<li>Do I really need to call objc_msgSend_fpret for floating point on Intel?</li>

<li>Is there a comprehensive reference to this subject that I'm missing?</li>
</ul>

<h2>And Some Answers</h2>

<p>Pending a re-write of this page, some very helpful answers can be found on the 
<a href="http://lists.apple.com/archives/cocoa-dev/2008/Feb/msg02335.html">
Cocoa-dev Mailing List</a>.</p>

</body>